package com.funcity.data
{
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.utils.getQualifiedClassName;
	
	public final class DataProvider extends EventDispatcher
	{
		private var _data:Object;
		
		public function DataProvider()
		{
			super(null);
		}
		
		public function set data(data:Object):void
		{
			_data = data;
			
			for (var property:String in _data)
			{
				dispatchEvent(new Event(property));
			}
		}
		
		public function getProperty(property:String):Object
		{
			return _data[property];
		}
				
		public function update(property:String, value:Object):void
		{
			var fields:Array = property.split(".");

			// get the data according to the property
			var field:String = fields.shift();
			var data:Object = _data;
			var event:String = field;
		
			while (fields.length != 0)
			{
				data = data[field];
				
				if (getQualifiedClassName(data) != "Object")
				{
					break;
				}
				field = fields.shift();
			}
			
			// if the attribute doesn't exist, return immediately
			if (fields.length != 0)
			{
				trace("Fail to update nonexist attribute " + property);
				return;
			}
			
			// if the attribute is null or value is null, assign directly
			if (data[field] == null || value == null)
			{
				data[field] = value;
			}
			else if (!updateField(data, field, value))
			{
				trace("Fail to update field " + field + " with " + typeof(value) + " value");
				return;
			}
			// trigger event for the property
			dispatchEvent(new Event(event));
		}
		
		private function updateField(data:Object, field:String, value:Object):Boolean
		{
			switch (getQualifiedClassName(data[field]))
			{
				case "Array":
					return updateArray(data, field, value);
				case "Object":
					return updateTable(data, field, value);
				default:
					data[field] = value;
					return true;
			};
		}
		
		private function updateArray(data:Object, field:String, value:Object):Boolean
		{
			if (getQualifiedClassName(value) != "Array")
			{
				return false;
			}
			
			var array:Array = data[field] as Array;
			return true;
		}
		
		private function updateTable(data:Object, field:String, value:Object):Boolean
		{
			if (getQualifiedClassName(value) != "Object")
			{
				return false;
			}
		
			var table:Object = data[field];
			for (var key:String in value)
			{
				table[key] = value[key];
			}
			return true;
		}		
	}
}